package com.google.code.sysarch.v1.e34;

import java.awt.Color;
import javax.swing.*;

class iThread extends Thread {

	public final static Color FOREGROUND_COLOR = new Color(255, 200, 0);
	public final static Color INTERACTIVE_THREAD_COLOR = new Color(255, 0, 0); 
	public final static Color BALANCED_THREAD_COLOR = new Color(0, 255, 0); 
	public final static Color COMPUTATIONALLYINTENSIVE_THREAD_COLOR = new Color(0, 0, 255); 
	 
	public final static int PSEUDO_OUTPUT_TIME = 1000;		// in ms
	public final static double PSEUDO_OUTPUT_CHANCE = 35;	// in percent
	
	public static Scheduler myScheduler;
	public int ThreadType = 0;	/*	0	interactive
							 	 *	1	balanced
							 	 *	2	computationally intensive
							 	 */
	private JProgressBar progressBar;
	private boolean running = false;
	private boolean isInteractive = false;
	private boolean didOutput = false;
	private int initialWork = 0;
	private int work = 0;
	private int timeslice = 1000;			// current timeslice: 1x for interactive threads, 2x for balanced and 4x for computationally intensive threads
	private int defaultTimeslice  = 1000;	// default timeslice which is multiplicated with 1, 2 or 4 to get 'timeslice'
	
	
	iThread(int work) {
		this.work = work;
		this.initialWork = work;
	}
	
	public void run() {
	
		/* This block is synchronized, but only to its own thread object
			More than one thread may be working concurrently within this block
		*/
		while (this.work > 0) {
			synchronized (this) {
				if (this.running) {
					calculate();
					this.updateProgress();
				} else {
					
					// determin thread-type
					if (!didOutput) {
						if (ThreadType == 1) ThreadType = 2;	// rule 2: balanced => computationally intensive
						if (ThreadType == 0) ThreadType = 1; 	// rule 1: interactive => balanced
					} else {
						ThreadType = 0;		// rule 4: after output => interactive
					}
					
					// queue it and wait for new timeslice
					myScheduler.queue(this);
					try {
						this.wait();
					} catch (InterruptedException e) { }
					
					// probably do output
					if (isInteractive) {
						if (Math.random()*100 < PSEUDO_OUTPUT_CHANCE) {
							pseudoOutput();
							didOutput = true;
						} else {
							didOutput = false;
						}
					}
				}
			}	
		}

		// call the Scheduler
		myScheduler.interrupt();
	}
	
	// the scheduler will call this method to allow/disallow the thread to run
	public void setRunning(boolean run) {
		this.running = run;
	}
	
	// Do some stupid work
	public void calculate() {
		this.work--;
		calcPrimes(10000);
	}
	
	public void pseudoOutput() {
		progressBar.setString("Performing IO");
		myScheduler.interrupt(); // call the Scheduler
		try {
			// thread is not queued while he is waiting, so he won't be interrupted
			int waitTime = (int) (PSEUDO_OUTPUT_TIME*(Math.random()*3+1));			
			wait(waitTime);
		} catch (InterruptedException e) { }
		progressBar.setString(null);
	}
	
	// calculates primes without saving the results, how stupid is that???
	public void calcPrimes(int n) {
		for (int i = 0; i < n; i++) {
			isPrime(i);
		}
	}
	
	// Returns true when number is a prime number
	public boolean isPrime(int number) {
		int root = (int) Math.ceil(Math.sqrt(number));
		if (number == 2) { return true; }
		if ((number & 1) == 0) { return false; }
		for (int div = 3; div <= root; div++) {
			if (number % div == 0) { return false; }
		}
		return true;
	}
	
	// functions to set and get 'timeslice' and 'default timeslice' this threads uses 
	public void setTimeslice(int timeslice) {
		this.timeslice = timeslice;
	}
	
	public void setDefaultTimeslice(int timeslice) {
		this.defaultTimeslice = timeslice;
		setTimeslice(timeslice);
	}
	
	public int getTimeslice() {
		return this.timeslice;
	}
	
	public int getDefaultTimeslice() {
		return this.defaultTimeslice;
	}
	
	// functions for the GUI
	public void updateProgress() {
		int progress = (int) Math.floor(100.0f * (this.initialWork - this.work) / this.initialWork);
		this.progressBar.setValue(progress);
	}
	
	public void setProgressBar(JProgressBar p) {
		this.progressBar = p;
	}
	
	public void setColor(Color c) {	// sets color of progress bar
		progressBar.setBackground(c);
	}

	public void defineAsInteractive() {
		isInteractive = true;	// mark thread as interactive
		didOutput = true;
		//progressBar.setFont(new Font("Dialog", Font.ITALIC, 8));
		progressBar.setForeground(FOREGROUND_COLOR);
		setColor(INTERACTIVE_THREAD_COLOR);
	}
	
	public boolean isInteractive() {
		return isInteractive;
	}

	
}